/*
 * Copyright (C) 2020 The LINN Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */

package com.juqimiao.linn.context;

import com.juqimiao.linn.exception.BasicError;
import com.juqimiao.linn.exception.SystemException;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.lang.Nullable;

import java.util.Map;

/**
 * The proxy of {@link ApplicationContext}.
 *
 * @author Collin Cai
 */

public class ApplicationContextWrapper implements ApplicationContextWrapperI {

    /* ---- Static ---------- */

    private static final String ERR_TEMPLATE = "Component %s can not be found in Spring Container.";
    private ApplicationContext applicationContext;

    /* ---- Property ---------- */

    /**
     * 设置一个 {@link ApplicationContext} 对象实例。
     *
     * @param applicationContext 一个 {@link ApplicationContext} 对象实例。
     */
    public void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }

    /* ---- Methods ---------- */

    /**
     * 获取一个Bean对象。
     *
     * @param targetClz {@link Class<?>} 类型。
     * @param <T>       任意类型。
     * @return          一个 bean 对象。
     */
    @Override
    public <T> T getBean(Class<T> targetClz) {
        T instance = null;
        try {
            instance = this.getBeanWithType(targetClz);
        } catch (Exception e) {
            // Todo: Need to put some logic in this section?
        }

        if (instance == null) {
            String simpleName = this.makeRightName(targetClz);
            @SuppressWarnings("unchecked")
            T t = (T) this.getBean(simpleName);
            instance = t;
        }

        if (instance == null) {
            String msg = String.format(ERR_TEMPLATE, targetClz);
            throw new SystemException(BasicError.FRAMEWORK_ERROR, msg);
        }
        return instance;
    }

    /**
     * 通过类型简单名称尝试获取bean对象。
     *
     * @param claz  类型全名。
     * @return      一个对象或null。
     */
    @Override
    public Object getBean(String claz) {
        return this.applicationContext.getBean(claz);
    }

    /**
     * 通过对象类型获取一个bean对象。
     *
     * @param type 表示一个泛化或抽象类型的{@link Class<?>}。
     * @param <T>   任意类型。
     * @return  一个包含多个bean对象的Map。
     */
    @Override
    public <T> Map<String, T> getBeansOfType(@Nullable Class<T> type) {
        return applicationContext.getBeansOfType(type);
    }

    private <T> String makeRightName(Class<T> targetClz) {

        String simpleName = targetClz.getSimpleName();
        simpleName = Character.toLowerCase(simpleName.charAt(0)) + simpleName.substring(1);
        return simpleName;
    }

    private <T> T getBeanWithType(Class<T> targetClz) {
        return this.applicationContext.getBean(targetClz);
    }


}
